#pragma once

#include "Config.h"
#include "Render.h"
#ifdef BUILD_D3D10

//For debugging stuff
#define D3D_DIAG_DLL

#include <vector>
#include <string>
#include <windows.h>
#include <d3d10.h> 
#include <d3dx10.h>
#include <D3DX10Core.h>

#define AS_D3D10_COM(r) ((IUnknown*)r)
#define AS_D3D10_RESOURCE(r) ((ID3D10Resource*)r)
#define RELEASE_D3D10_RESOURCE(r) if(r) { AS_D3D10_RESOURCE(r)->Release(); r = NULL; }


class CD3D10 : public Render {
private:
	static ID3D10Device*		g_pd3dDevice;

	static ID3D10Query*			g_pSOQuery;
    static ID3D10StateBlock*	g_pStateBlock;
	static ID3DX10Sprite*		g_pSpriteBatch;
	static ID3DX10Sprite*		g_pFontBatch;
	static ID3DX10Font*			g_pd3dxFontBody;
	
	static ID3D10BlendState*	g_pBlendState;
	/*static ID3D10DepthStencilState*	g_pDepthStencilState;*/
	static ID3D10RasterizerState* g_pRasterizeState;

	static ID3DX10Font*			g_pd3dxFontTitle;
	static ID3D10Effect*		g_pStateEffect;
	static HANDLE				g_ShaderCompiling;


	static IDXGISwapChain*		g_pSwapChain;
	static ID3D10RenderTargetView* g_pRenderTargetView;
	static ID3D10DepthStencilView* g_pRenderDepthStencilView;

	static struct tCurrentShader
	{
		ID3D10Effect*		m_pEffect;
		ID3D10EffectTechnique*	m_pTechnique;
		UINT	m_OnPass;

		void Set(ID3D10Effect* pEffect,	ID3D10EffectTechnique* pTechnique) { m_pEffect = pEffect; m_pTechnique = pTechnique; }
		bool IsValid() { return m_pEffect && m_pTechnique; }
	} g_pCurrentShader;

	bool GetTextureView(tResource* pTexture, ID3D10ShaderResourceView** pOut);
	bool GetTextureResource(tResource* pTexture, ID3D10Resource** pOut, UINT *pDimensions);

	static D3D10_RESOURCE_DIMENSION GetD3D10Type(Render::tResource* pResource);
	static bool HasTechnique(ID3D10Effect* pEffect, LPCSTR pTechnqiueName);
	
	
	bool GetShaderVariable(ID3D10Effect* pShader, LPCSTR pName, ID3D10EffectVariable** pOut);
	bool CreateBuffer(D3D10_BUFFER_DESC desc, tResource** pInOut);

	static bool GetTechniquePassDesc(ID3D10Effect* pEffect, LPCSTR pTechnqiueName, UINT passIdx, D3D10_PASS_DESC *pPassDesc);
	static bool ReleaseShaderMacros(std::vector<D3D10_SHADER_MACRO> *pMacros);
	static bool GetShaderMacrosAndElements(const uint VertexFormat, const uint Attributes, std::vector<D3D10_INPUT_ELEMENT_DESC> *pOutElements, std::vector<D3D10_SHADER_MACRO> *pOutMacros);
protected:

	
static DWORD WINAPI ShaderCompileWorker( LPVOID lpParam);


public:
	
	bool GetShader(const std::string& filename, const uint VertexFormat, const uint Attributes, Render::tShader** pInOut = NULL, bool forceReload = true, LPVOID pDevice = NULL);
	bool ReleaseShader(Render::tShader** pInOut);
	bool CreateTexture(const std::string& filename, Render::tResource** pOut = NULL, LPVOID pDevice = NULL);
	bool GetTexture(const std::string& filename, Render::tResource** pOut);

	void SetShaderTexture(DWORD Stage, tResource* pTexture);
	bool GetTextureInfo(tResource* pTexture, UINT* pWidth, UINT* pHeight);
	bool GetBufferInfo(tResource* pBuffer, UINT* pSizeInBytes);

	bool Create(HWND hWnd);
	bool Release();
	bool ReloadResources();

	bool CreateVertexIndicieBuffer(UINT sizeBytes, LPVOID pData, uint vertexFormat, tResource** pVBOut, tResource** pIBOut);
	bool CreateIndexBuffer(UINT sizeBytes, tResource** pInOut);
	bool CreateVertexBuffer(UINT sizeBytes, bool isStreamOut, tResource** pInOut);
	bool FillVertexBuffer(tResource* pVertexBuffer, UINT sizeInBytes, LPVOID pData);
	bool BindVertexBuffer(tResource** pVertexBuffers, UINT* elementSizes, UINT BufferCount);
	bool BindIndexBuffer(tResource* pIndexBuffer, UINT elementSize);
	bool BindStreamOutBuffer(tResource* pStreamOutBuffer, UINT elementSize);
	bool DrawIndexedTriangleList(UINT triangelCount, UINT* pInstanceCount, UINT *pDeformationPass);
	bool DrawTriangleList(UINT elementCount, UINT* pInstanceCount);
	bool DrawLineList(UINT elementCount);
	//bool StreamOutToBuffer(tPart* pParentMesh, D3DXMATRIX* pWorld, Render::tResource* pInstanceBuffer,uint* pPrimitvesWritten);
	bool StreamOutToBuffer(tPart* pParentMesh, Render::tResource* pCookie,int uvChannel, D3DXMATRIX* pWorld, tInstanceChild* pChild,uint* pPrimitvesWritten);
	
	bool ReleaseResource(tResource** pResource);

	bool SetShaderMatrix(LPCSTR pName, D3DXMATRIX* pValue);
	bool SetShaderVector(LPCSTR pName, D3DXVECTOR4* pValue);
	bool SetShaderFloat(LPCSTR pName, float value);
	bool SetShaderInt(LPCSTR pName, int value);

	bool BeginShader(const Render::tShader* pShader, bool isInstanced, UINT* pPasses);
	bool EndShader();
	bool BeginShaderPass(UINT pass);
	bool EndShaderPass();

	bool BeginSprites();
	bool EndSprites();
	void DrawSprite(tResource* pTexture, D3DXVECTOR2& position, D3DXVECTOR2& scale, RECT* pSrc);
	void DrawString(DWORD type, D3DCOLOR color, D3DXVECTOR2& position, char* format, ...);

	void BeginRendering();
	void EndRendering();
};

#endif